﻿using Lt.Engine.Types;
using RayDen.Library.Components;
using RayDen.Library.Components.Color;
using RayDen.Library.Components.Surface;
using RayDen.Library.Core.Primitives;

namespace Lt.Engine.Sampling
{
    public abstract class BaseBsdf : BrdfBase, IBsdf
    {
        protected internal ONB frame;
        protected internal Normal Ns, Ng;
        protected internal Point HitPoint;
        public void Setup(RayIntersection isect)
        {
            /*
                nn = n.ToVec().Normalize();
            Vector.CoordinateSystem(ref nn, out sn, out tn);
             */
            frame = new ONB();
            frame.SetFromZ(ref isect.ShadingNormal); // TODO isect.GeoNormal
            Ns = isect.ShadingNormal;
            Ng = isect.GeoNormal;
            HitPoint = isect.Hitpoint;
        }

        public abstract IRadianceEvaluation Sample(ref Vector wo, ref IRadianceEvaluation radiance, float u0, float u1,
            float u2, out BsdfSample result, BrdfType flags = BrdfType.All);


        public abstract IRadianceEvaluation Evaluate(LtScene aScene, ref Vector aWorldDirGen, float oCosThetaGen,
            out float oDirectPdfW,
            out float oReversePdfW);

        public abstract float Pdf(LtScene aScene, ref Vector aWorldDirGen, bool aEvalRevPdf = false);

        public override bool IsLightSource()
        {
            return false;
        }

        public override bool IsDiffuse()
        {
            return Has(Type, BrdfType.Diffuse);
        }

        public override bool IsRefractive()
        {
            return Has(Type, BrdfType.Refractive);
        }

        public override bool IsSpecular()
        {
            return Has(Type, BrdfType.Specular);
        }

        public static bool Has(BrdfType val, BrdfType f)
        {
            //return val.HasFlag(f);
            return ((uint)val & (uint)f).Equals((uint)f);
        }

        public Vector WorldToLocal(ref Vector v)
        {

            return frame.ToLocal(ref v);
        }
        public Vector LocalToWorld(ref Vector v)
        {
            return frame.ToWorld(ref v);
        }
    }
}